package cc.owoo.godpen.util;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.image.BufferedImage;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 计算工具类
 * Created by nimensei
 * 2020-05-12 下午 06:20
 **/
public class N {
    private static final char[] HEX_CHARS = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};// 字节数组转16进制的字符
    public static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 日期转换

    /**
     * 生成MD5字符串
     *
     * @param string 需要计算md5值的字符串
     * @return 生成的MD5字符串
     */
    public static String md5(String string) {
        if (string == null)
            return null;
        return md5(string.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成MD5字符串
     *
     * @param bytes 需要计算md5值的数据
     * @return 生成的MD5字符串
     */
    public static String md5(byte[] bytes) {
        if (bytes == null)
            return null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("md5");
            return new String(encodeHex(md5.digest(bytes)));
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }

    /**
     * 将字节数组编码为16进制字符串
     *
     * @param bytes 需要编码的字节数组
     * @return 编码后的字符串
     */
    public static char[] encodeHex(byte[] bytes) {
        char[] chars = new char[32];
        for (int i = 0; i < chars.length; i += 2) {
            byte b = bytes[i / 2];
            chars[i] = HEX_CHARS[b >>> 4 & 15];
            chars[i + 1] = HEX_CHARS[b & 15];
        }
        return chars;
    }

    public static void main(String[] args) {
        System.out.println(md5("hello"));
    }

    /**
     * 将字符转换成unicode数字字符串
     *
     * @param c 需要转换的字符、数字
     * @return unicode数字字符串
     */
    public static String unicode(int c) {
        return before(Integer.toHexString(c & 0xFFFF), 4, '0');
    }

    /**
     * 将byte转换成十六进制字符
     *
     * @param n 需要转换的字节
     * @return 转换后的十六进制字符
     */
    public static char[] hex(byte n) {
        byte b = (byte) (n >> 4 & 0xF);
        n &= 0xF;
        return new char[]{(char) ((b < 10 ? 48 : 87) + b), (char) ((n < 10 ? 48 : 87) + n)};
    }

    /**
     * unicode编码，将字符串中的非ASCII码转换成unicode字符串
     *
     * @param stringBuilder 转换后的字符串
     * @param translate     字符转换器，ASCII码会调用转换器，如果转换器的返回值不为空，则添加'\'后再添加转换后的字符
     * @param string        需要转换的字符串
     */
    public static void encodeUnicode(StringBuilder stringBuilder, String string, CharacterTranslate translate) {
        for (char c : string.toCharArray()) {
            if (c < 128) {
                String character = translate == null ? null : translate.translate(c);
                if (character == null)
                    stringBuilder.append(c);
                else
                    stringBuilder.append(character);
                continue;
            }
            stringBuilder.append("\\u").append(hex((byte) (c >> 8))).append(hex((byte) c));
        }
    }

    /**
     * unicode编码，将字符串中的非ASCII码转换成unicode字符串
     *
     * @param string    需要转换的字符串
     * @param translate 字符转换器，ASCII码会调用转换器，如果转换器的返回值不为空，则添加'\'后再添加转换后的字符
     * @return 转换为unicode后的字符串
     */
    public static String encodeUnicode(String string, CharacterTranslate translate) {
        StringBuilder stringBuilder = new StringBuilder();
        encodeUnicode(stringBuilder, string, translate);
        return stringBuilder.toString();
    }

    /**
     * unicode解码，将带有转义符的字符串转换为正常的字符串，例如将\t、\u0000转换成为原本的字符
     *
     * @param stringBuilder 转换后的字符串
     * @param string        需要转换的字符串
     */
    public static void decodeUnicode(StringBuilder stringBuilder, String string) {
        parseEscape(stringBuilder, string.toCharArray(), 0, (char) Integer.MAX_VALUE);
    }

    /**
     * unicode解码，将带有转义符的字符串转换为正常的字符串，例如将\t、\u0000转换成为原本的字符
     *
     * @param string 需要转换的字符串
     * @return 转换后的字符串
     */
    public static String decodeUnicode(String string) {
        StringBuilder stringBuilder = new StringBuilder();
        decodeUnicode(stringBuilder, string);
        return stringBuilder.toString();
    }

    /**
     * 解析字符串
     *
     * @param string 解析后的字符串
     * @param chars  需要解析的字符串
     * @param index  解析位置
     * @param end    结束符
     * @return 遍历结束的位置
     */
    public static int parseEscape(StringBuilder string, char[] chars, int index, char end) {
        int unicodeIndex = 0;
        int unicodeNumber = 0;
        boolean isTranslate = false;
        while (index < chars.length) {
            char c = chars[index++];
            if (unicodeIndex > 0) {
                unicodeNumber <<= 4;
                unicodeNumber |= c - (c >= 'a' ? 87 : c >= 'A' ? 55 : '0');
                if (--unicodeIndex == 0) {
                    string.append((char) unicodeNumber);
                    unicodeNumber = 0;
                }
                continue;
            }
            if (isTranslate) {
                if (c == 'u')
                    unicodeIndex = 4;
                else {
                    if ((c == '\'' || c == '"') && c != end)
                        string.append('\\').append(c);
                    else
                        string.append(parseEscape(c));
                }
                isTranslate = false;
                continue;
            }
            if (c == '\\') {
                isTranslate = true;
                continue;
            }
            if (c == end)
                break;
            string.append(c);
        }
        return index;
    }

    /**
     * 将特殊字符转成转义字符
     *
     * @param c 需要转义的字符
     * @return 转义后的字符，如果不能转换则返回字符本身
     */
    public static String escape(char c) {
        return switch (c) {
            case '\0' -> "\\0";
            case '\'' -> "\\'";
            case '"' -> "\\\"";
            case '\\' -> "\\\\";
            case '\t' -> "\\t";
            case '\n' -> "\\n";
            case '\b' -> "\\b";
            case '\r' -> "\\r";
            case '\f' -> "\\f";
            default -> String.valueOf(c);
        };
    }

    /**
     * 将转义字符转成原字符
     *
     * @param c 需要转义的字符
     * @return 转义后的字符
     */
    public static char parseEscape(char c) {
        return switch (c) {
            case '0' -> '\0';
            case 't' -> '\t';
            case 'n' -> '\n';
            case 'b' -> '\b';
            case 'r' -> '\r';
            case 'f' -> '\f';
            default -> c;
        };
    }

    /**
     * 生成一个UUID，并去除横线
     *
     * @return 随机UUID
     */
    public static String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 编码为Base64
     *
     * @param bytes 需要编码的数据
     * @return 编码后的字符串
     */
    public static String encodeBase64(byte[] bytes) {
        try {
            return new String(Base64.getEncoder().encode(bytes));
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 解码Base64
     *
     * @param code base编码
     * @return 解码后的数据
     */
    public static byte[] decodeBase64(String code) {
        try {
            return Base64.getDecoder().decode(code);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 解码Base64
     *
     * @param s 需要解码的字符串
     * @return 解码后的字符串
     */
    public static String decodeBase64(String s, String coding) {
        try {
            return new String(Base64.getDecoder().decode(s), coding);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 将对象数组转换成LinkedList集合
     *
     * @param array 需要转换的对象数组
     * @param <E>   对象类型
     * @return LinkedList
     */
    public static <E> LinkedList<E> toLinkedList(E[] array) {
        return new LinkedList<>(Arrays.asList(array));
    }

    /**
     * 设置文本到剪切板
     *
     * @param content 需要设置的内容
     */
    public static void setClipboard(String content) {
        Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable transferable = new StringSelection(content);
        clip.setContents(transferable, null);
    }

    /**
     * 设置图片到剪切板
     *
     * @param image 需要设置的图片
     */
    public static void setClipboard(BufferedImage image) {
        Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new ClipboardImage(image), null);
    }

    /**
     * 获取剪切板内容
     *
     * @return 剪切板内容，该对象不会为空
     */
    public static ClipboardContent getClipboard() {
        ClipboardContent clipboardContent = new ClipboardContent();
        try {
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            Transferable transferable = clipboard.getContents(null);
            clipboardContent.content = transferable.getTransferData(DataFlavor.stringFlavor);
            if (transferable.isDataFlavorSupported(DataFlavor.stringFlavor))
                clipboardContent.type = ClipboardContentType.TEXT;
            else if (transferable.isDataFlavorSupported(DataFlavor.imageFlavor))
                clipboardContent.type = ClipboardContentType.IMAGE;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clipboardContent;
    }

    /**
     * 剪切板内容
     */
    public static class ClipboardContent {
        public Object content;// 内容
        public ClipboardContentType type;// 内容类型

        /**
         * 获取文本
         *
         * @return 获取文本
         */
        public String getText() {
            if (type != ClipboardContentType.TEXT)
                return null;
            return (String) content;
        }

        /**
         * 获取图片
         *
         * @return 获取图片
         */
        public BufferedImage getImage() {
            if (type != ClipboardContentType.IMAGE)
                return null;
            return (BufferedImage) content;
        }

        /**
         * 内容是否为null
         *
         * @return 内容是否为null
         */
        public boolean isNull() {
            return content == null;
        }

        @Override
        public String toString() {
            return String.valueOf(content);
        }
    }

    /**
     * 剪切板内容类型
     */
    public enum ClipboardContentType {
        TEXT, IMAGE
    }

    /**
     * 剪切板图片
     */
    private record ClipboardImage(BufferedImage image) implements Transferable {
        public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[]{DataFlavor.imageFlavor};
        }

        public boolean isDataFlavorSupported(DataFlavor flavor) {
            return DataFlavor.imageFlavor.equals(flavor);
        }

        public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
            if (!DataFlavor.imageFlavor.equals(flavor))
                throw new UnsupportedFlavorException(flavor);
            return image;
        }
    }


    /**
     * 裁剪字符串，调用的为String的split
     *
     * @param string   需要裁剪的字符串
     * @param interval 间隔符号
     * @return 裁剪后的字符串数组
     */
    public static String[] split(String string, String interval) {
        return string.split(interval);
    }

    /**
     * 裁剪字符串，与String自带的split相比，该函数的分隔符为char，且不做任何转义处理
     *
     * @param string   需要裁剪的字符串
     * @param interval 间隔符号
     * @return 裁剪后的字符串数组
     */
    public static String[] split(String string, char interval) {
        if (string == null)
            throw new NullPointerException("字符串不能为空");
        LinkedList<String> list = new LinkedList<>();
        int before = 0;
        int index = 0;
        while (index < string.length()) {
            index = string.indexOf(interval, index);
            if (index == -1)
                break;
            list.add(string.substring(before, index));
            before = ++index;
        }
        if (before < string.length())
            list.add(string.substring(before));
        return list.toArray(new String[0]);
    }

    /**
     * 合并字符串
     *
     * @param array    需要合并的字符串数组
     * @param interval 分隔符
     * @return 合并后的字符串
     */
    public static String join(String[] array, char interval) {
        return join(Arrays.asList(array), String.valueOf(interval));
    }

    /**
     * 合并字符串
     *
     * @param array    需要合并的字符串数组
     * @param interval 分隔符
     * @return 合并后的字符串
     */
    public static String join(String[] array, String interval) {
        return join(Arrays.asList(array), interval);
    }

    /**
     * 合并字符串
     *
     * @param collection 需要合并的字符串数组
     * @param interval   分隔符
     * @return 合并后的字符串
     */
    public static String join(Collection<? extends String> collection, char interval) {
        return join(collection, String.valueOf(interval));
    }

    /**
     * 合并字符串
     *
     * @param collection 需要合并的字符串数组
     * @param interval   分隔符
     * @return 合并后的字符串
     */
    public static String join(Collection<? extends String> collection, String interval) {
        if (collection == null)
            throw new NullPointerException("数组不能为空");
        StringBuilder string = new StringBuilder();
        for (String s : collection) {
            if (string.length() > 0 && interval != null)
                string.append(interval);
            string.append(s);
        }
        return string.toString();
    }

    /**
     * 获取日期，对SimpleDateFormat和Date的一个简单封装，可以快速通过format格式获取当前的日期
     *
     * @param format 格式化表达式
     * @return 日期字符串
     */
    public static String getDate(String format) {
        return getDate(new Date(), format);
    }

    /**
     * 获取日期，对SimpleDateFormat和Date的一个简单封装，可以将日期格式化后返回
     *
     * @param date   日期对象
     * @param format 格式化表达式
     * @return 日期字符串
     */
    public static String getDate(Date date, String format) {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(d);
    }

    /**
     * 获取日期，对SimpleDateFormat和Date的一个简单封装，可以将日期格式化后返回
     *
     * @param date   日期字符串
     * @param format 格式化表达式
     * @return 日期对象
     */
    public static Date getDate(String date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            return sdf.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将float转换为int，与Java自带的Math.round相比，这个采用(int)(value+0.5)的转换方式，可以提高效率
     *
     * @param number 需要转换的值
     * @return 转换后的值
     */
    public static int toInt(float number) {
        return (int) (number + (number < 0 ? -0.5f : 0.5f));
    }

    /**
     * 将double转换为int，与Java自带的Math.round相比，这个采用(int)(value+0.5)的转换方式，可以提高效率
     *
     * @param number 需要转换的值
     * @return 转换后的值
     */
    public static int toInt(double number) {
        return (int) (number + (number < 0 ? -0.5 : 0.5));
    }

    /**
     * 将float转换为long，与Java自带的Math.round相比，这个采用(long)(value+0.5)的转换方式，可以提高效率
     *
     * @param number 需要转换的值
     * @return 转换后的值
     */
    public static long toLong(float number) {
        return (long) (number + (number < 0 ? -0.5f : 0.5f));
    }

    /**
     * 将double转换为long，与Java自带的Math.round相比，这个采用(long)(value+0.5)的转换方式，可以提高效率
     *
     * @param number 需要转换的值
     * @return 转换后的值
     */
    public static long toLong(double number) {
        return (long) (number + (number < 0 ? -0.5 : 0.5));
    }

    /**
     * 将字符串转换成int，和Java自带的Integer.parse()相比，这个不会抛出异常，
     * 如果字符串后面有非数字字符，仍然可以返回前面的数字，例如传入"12ab"，则会返回12
     *
     * @param s 需要转换的字符串
     * @return 转换后的数字，如果转换失败，则会返回0
     */
    public static int toInt(String s) {
        return toInt(s, 0);
    }

    /**
     * 将字符串转换成int，和Java自带的Integer.parse()相比，这个不会抛出异常，
     * 如果字符串后面有非数字字符，仍然可以返回前面的数字，例如传入"12ab"，则会返回12
     *
     * @param s   需要转换的字符串
     * @param num 转换失败的默认值
     * @return 转换后的数字
     */
    public static int toInt(String s, int num) {
        return (int) toLong(s, num);
    }

    /**
     * 将字符串转换成long，和Java自带的Long.parse()相比，这个不会抛出异常，
     * 如果字符串后面有非数字字符，仍然可以返回前面的数字，例如传入"12ab"，则会返回12
     *
     * @param s 需要转换的字符串
     * @return 转换后的数字，如果转换失败，则会返回0
     */
    public static long toLong(String s) {
        return toLong(s, 0);
    }

    /**
     * 将字符串转换成int，和Java自带的Long.parse()相比，这个不会抛出异常，
     * 如果字符串后面有非数字字符，仍然可以返回前面的数字，例如传入"12ab"，则会返回12
     *
     * @param s   需要转换的字符串
     * @param num 转换失败的默认值
     * @return 转换后的数字
     */
    public static long toLong(String s, long num) {
        if (s == null)
            return num;
        s = s.trim();
        num = 0;
        boolean isNum = false;
        for (char c : s.toCharArray()) {
            if (c < '0' || c > '9') {
                if (isNum)
                    break;
                continue;
            }
            num = num * 10 + (c - '0');
            isNum = true;
        }
        return num;
    }

    /**
     * 将字符串转换成float
     *
     * @param s 字符串
     * @return float值
     */
    public static float toFloat(String s) {
        return toFloat(s, 0);
    }

    /**
     * 将字符串转换成float
     *
     * @param s   字符串
     * @param num 如果转换失败，则返回这个值
     * @return float值
     */
    public static float toFloat(String s, float num) {
        try {
            return Float.parseFloat(s);
        } catch (NumberFormatException e) {
            return num;
        }
    }

    /**
     * 将字符串转换成double
     *
     * @param s 字符串
     * @return double值
     */
    public static double toDouble(String s) {
        return toDouble(s, 0);
    }

    /**
     * 将字符串转换成double
     *
     * @param s   字符串
     * @param num 如果转换失败，则返回这个值
     * @return double值
     */
    public static double toDouble(String s, double num) {
        try {
            return Double.parseDouble(s);
        } catch (NumberFormatException e) {
            return num;
        }
    }

    /**
     * 向上取整
     */
    public static int occupied(double number) {
        int n = (int) number;
        if (n == number)
            return n;
        else
            return n + 1;
    }

    /**
     * 在数字前面填充字符c，并返回字符串对象,使字符串的长度不小于len
     *
     * @param text 字符串
     * @param len  长度
     * @param c    字符
     * @return 字符串
     */
    public static String before(String text, int len, char c) {
        len -= text.length();
        if (len <= 0)
            return text;
        StringBuilder string = new StringBuilder();
        pow(String.valueOf(c), len, string);
        string.append(text);
        return string.toString();
    }

    /**
     * 在数字前面填充0，并返回字符串对象,使字符串的长度不小于len
     *
     * @param number 需要填充0的值
     * @param len    字符串的长度不小于len
     * @return 字符串
     */
    public static String before(int number, int len) {
        return before(String.valueOf(number), len, '0');
    }

    /**
     * 保留小数精度
     */
    public static String toFixed(double number, int len) {
        boolean lose = number < 0;
        if (lose)
            number = -number;
        StringBuilder string = new StringBuilder();
        long longValue = (long) number;
        string.append(String.valueOf(longValue));
        number -= longValue;
        boolean dot = false;
        while (number != 0 && --len >= 0) {
            if (!dot) {
                string.append('.');
                dot = true;
            }
            number *= 10;
            longValue = (long) number;
            string.append(longValue % 10);
            number -= longValue;
        }
        if (lose)
            string.insert(0, '-');
        return string.toString();
    }

    /**
     * 将double浮点数转成定点数二进制
     *
     * @param number 需要转换的值
     * @return 转换后的字符串
     */
    public static String toBinaryString(double number) {
        StringBuilder string = new StringBuilder();
        long longValue = (long) number;
        string.append(toBinaryString(longValue));
        number -= longValue;
        boolean dot = false;
        int count = 0;
        while (number != 0) {
            if (!dot) {
                string.append('.');
                dot = true;
            }
            number *= 2;
            longValue = (long) number;
            string.append(longValue % 2);
            number -= longValue;
            ++count;
        }
        if (count != 64)
            pow("0", 64 - count, string);
        return string.toString();
    }

    /**
     * 计算有效的二进制长度，及这个二进制转换成字符串后的长度为多少
     *
     * @param number 需要计算的数值
     * @return 二进制长度
     */
    public static int binaryLength(long number) {
        if (number == 0)
            return 0;
        if (number < 0)
            number = ~number + 1;
        int count;
        if (number >= 1L << 48)
            number >>= count = 48;
        else if (number >= 1L << 32)
            number >>= count = 32;
        else if (number >= 1L << 16)
            number >>= count = 16;
        else
            count = 0;
        while (number > 0) {
            number >>= 1;
            ++count;
        }
        return count;
    }

    /**
     * 将int数值转换成二进制字符串
     *
     * @param number 需要转换的数值
     * @return 转换成二进制字符串
     */
    public static String toBinaryString(int number) {
        return toBinaryString(number, 32);
    }

    /**
     * 将long数值转换成二进制字符串
     *
     * @param number 需要转换的数值
     * @return 转换后的二进制字符串
     */
    public static String toBinaryString(long number) {
        return toBinaryString(number, 64);
    }

    /**
     * 将整型数值转化为二进制字符串，长度为len
     *
     * @param number 需要转换的数值
     * @param len    字符串长度
     * @return 转换后的二进制字符串
     */
    public static String toBinaryString(long number, int len) {
        if (number == 0)
            return "0";
        if (number < 0)
            return minusToBinaryString(~number, len);
        else
            return positiveToBinaryString(number, len);
    }

    /**
     * 将负数转换成二进制字符串
     *
     * @param number 需要转换的数值
     * @param len    字符串长度
     * @return 转换后的二进制字符串
     */
    private static String minusToBinaryString(long number, int len) {
        StringBuilder string = new StringBuilder();
        while (number > 0 && len > 0) {
            string.insert(0, number % 2 == 1 ? 0 : 1);
            number >>= 1;
            --len;
        }
        if (len > 0)
            pow("1", len, string, 0);
        return string.toString();
    }

    /**
     * 将正数转换成二进制字符串
     *
     * @param number 需要转换的数值
     * @param len    字符串长度
     * @return 转换后的二进制字符串
     */
    public static String positiveToBinaryString(long number, int len) {
        StringBuilder string = new StringBuilder();
        while (number > 0) {
            string.insert(0, number % 2);
            number >>= 1;
        }
        return pow("0", len - string.length()) + string;
    }

    /**
     * 计算a的b次方，该函数只能计算int型次方，与Math.pow相比，这个采用快速幂
     *
     * @param a 数值
     * @param b 次方
     * @return 计算结果
     */
    public static int pow(int a, int b) {
        b = Math.max(0, b);
        int ans = 1;
        while (b > 0) {
            if (b % 2 == 1)
                ans *= a;
            a *= a;
            b >>= 1;
        }
        return ans;
    }

    /**
     * 计算a的b次方，该函数只能计算int型次方，与Math.pow相比，这个采用快速幂
     *
     * @param a 数值
     * @param b 次方
     * @return 计算结果
     */
    public static long pow(long a, int b) {
        b = Math.max(0, b);
        long ans = 1;
        while (b > 0) {
            if (b % 2 == 1)
                ans *= a;
            a *= a;
            b >>= 1;
        }
        return ans;
    }

    /**
     * 计算a的b次方，该函数只能计算int型次方，与Math.pow相比，这个采用快速幂
     *
     * @param a 数值
     * @param b 次方
     * @return 计算结果
     */
    public static double pow(double a, int b) {
        b = Math.max(0, b);
        double ans = 1;
        while (b > 0) {
            if (b % 2 == 1)
                ans *= a;
            a *= a;
            b >>= 1;
        }
        return ans;
    }

    /**
     * 字符串拼接
     *
     * @param a 需要复制拼接的字符串
     * @param b 复制次数
     * @return 拼接后的字符串
     */
    public static String pow(String a, int b) {
        if (a == null)
            return null;
        if (b <= 0)
            return "";
        if (a.length() == 0)
            return a;
        StringBuilder now = new StringBuilder(a);
        StringBuilder ans = new StringBuilder();
        while (b > 0) {
            if (b % 2 == 1)
                ans.append(now);
            now.append(now);
            b >>= 1;
        }
        return ans.toString();
    }

    /**
     * 字符串拼接
     *
     * @param a      需要复制拼接的字符串
     * @param b      复制次数
     * @param string 需要拼接的字符串
     */
    public static void pow(String a, int b, StringBuilder string) {
        if (a == null)
            return;
        if (a.length() == 0)
            return;
        b = Math.max(0, b);
        if (b == 0)
            return;
        StringBuilder now = new StringBuilder(a);
        while (b > 0) {
            if (b % 2 == 1)
                string.append(now);
            now.append(now);
            b >>= 1;
        }
    }

    /**
     * 字符串拼接
     *
     * @param a      需要复制拼接的字符串
     * @param b      复制次数
     * @param string 需要拼接的字符串
     * @param offset 从string的offset开始拼接
     */
    public static void pow(String a, int b, StringBuilder string, int offset) {
        if (a == null)
            return;
        if (a.length() == 0)
            return;
        b = Math.max(0, b);
        if (b == 0)
            return;
        StringBuilder now = new StringBuilder(a);
        while (b > 0) {
            if (b % 2 == 1)
                string.insert(offset, now);
            now.append(now);
            b >>= 1;
        }
    }

    private static final long[] overflowValue = {1296, 1679616, 2176782336L};// 相同时间戳数字溢出处理，实测以java的运行速度，连1679616都很难达到，intel core i5 11500@4.2Ghz最大为13722
    private static final int[] overflowLength = {2, 4, 6};// 数字溢出处理
    private static long oldSoleTime;// 上次生成的局部唯一的时间戳
    private static int soleIndex;// 相同唯一code出现的次数

    /**
     * 利用时间戳生成一个单局部唯一code，单个时间戳内最多可生成1296个不同字符串
     * <p>
     * （线程安全的）
     *
     * @return 唯一code
     */
    public static String soleCode() {
        long time;
        int index;
        synchronized (overflowValue) {
            time = System.currentTimeMillis();
            if (time != oldSoleTime) {
                oldSoleTime = time;
                index = soleIndex = 0;
            } else
                index = ++soleIndex;
        }
        String code = parse36(time);
        if (index == 0)
            return code + "00";
        int i = 0;
        while (i < overflowValue.length - 1 && overflowValue[i] <= index)
            ++i;
        return code + before(parse36(index % overflowValue[i]), overflowLength[i], '0');
    }

    /**
     * 将数字转换成26进制字符串
     *
     * @param num 需要转换的数字
     * @return 26进制字符串
     */
    public static String parse26(long num) {
        StringBuilder string = new StringBuilder();
        while (num > 0) {
            int now = (int) (num % 26);
            string.insert(0, (char) ('A' + now));
            num /= 26;
        }
        return string.toString();
    }

    /**
     * 将数字转换成36进制字符串
     *
     * @param num 需要转换的数字
     * @return 26进制字符串
     */
    public static String parse36(long num) {
        StringBuilder string = new StringBuilder();
        while (num > 0) {
            int now = (int) (num % 36);
            string.insert(0, (char) (now < 10 ? '0' + now : 'A' + (now - 10)));
            num /= 36;
        }
        return string.toString();
    }

    /**
     * 随机一个int数字
     *
     * @param max 最大值
     * @return 随机的结果
     */
    public static int random(int max) {
        if (max < 0)
            throw new IllegalAccessError();
        return (int) (Math.random() * max);
    }

    /**
     * 随机一个0 ~ 1的double值，不包含1
     *
     * @return 随机的结果
     */
    public static double random() {
        return Math.random();
    }

    /**
     * 随机一个boolean值
     *
     * @return 随机的结果
     */
    public static boolean randomBoolean() {
        return random() >= 0.5;
    }

    /**
     * 随机生成一串小字母的字符串
     *
     * @param length 字符串长度
     * @return 字符串
     */
    public static String randomCode(int length) {
        StringBuilder stringBuilder = new StringBuilder();
        while (--length >= 0)
            stringBuilder.append((char) (random(26) + 'a'));
        return stringBuilder.toString();
    }

    /**
     * 随机生成一串小字母的字符串
     *
     * @param length 字符串长度
     * @return 字符串
     */
    public static String randomCode(Random random, int length) {
        StringBuilder stringBuilder = new StringBuilder();
        while (--length >= 0)
            stringBuilder.append((char) (random.nextInt(26) + 'a'));
        return stringBuilder.toString();
    }

    /**
     * 是否为数字
     *
     * @param s 需要判断的字符串
     * @return 是否为数字
     */
    public static boolean isNumber(String s) {
        if (s == null)
            return false;
        for (int i = 0; i < s.length(); i++)
            if (s.charAt(i) < '0' || s.charAt(i) > '9')
                return false;
        return true;
    }

    /**
     * 将字节长度转化为字符串表示，例如2.3MB
     *
     * @param length 字节长度
     * @return 以字节为单位的大小
     */
    public static String size(double length) {
        return size(length, 2);
    }

    /**
     * 将字节长度转化为字符串表示，例如2.3MB
     *
     * @param size  字节长度
     * @param fixed 保留的小数点长度
     * @return 字符串表示的大小
     */
    public static String size(double size, int fixed) {
        if (size == 0)
            return "0B";
        byte count = 0;
        while (size >= 1024d || size <= -1024d) {
            size /= 1024d;
            ++count;
        }
        StringBuilder string = new StringBuilder(toFixed(size, fixed));
        switch (count) {
            case 0 -> string.append("B");
            case 1 -> string.append("KB");
            case 2 -> string.append("MB");
            case 3 -> string.append("GB");
            case 4 -> string.append("TB");
            case 5 -> string.append("PB");
            case 6 -> string.append("EB");
        }
        return string.toString();
    }

    /**
     * 字符转换器
     */
    public interface CharacterTranslate {
        String translate(char c);
    }
}
